package com.ht.yml.tools;

import com.alibaba.fastjson.JSON;
import com.ht.common.util.ListUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * @author wangmin
 * @discription
 * @created 2024-12-30 9:49
 */
public class YamlPropertiesUtils {
    public static String compare(
            Map<String, Object> yaml1, final String name1,
            Map<String, Object> yaml2, final String name2
    ) {
        System.out.println("\n\n\nbefore compare '" + name1 + "' and '" + name2 + "'↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
        final ArrayList<String> notSameMessages = new ArrayList<>();
        final ArrayList<String> sameMessages = new ArrayList<>();
        final Map<String, Object> leftNullMap = new HashMap<>();
        final Map<String, Object> rightNullMap = new HashMap<>();
        compare("", yaml1, yaml2, notSameMessages, sameMessages, leftNullMap, rightNullMap);
        if (!notSameMessages.isEmpty()) {
            System.out.println("下面属性都有配置, 但是不相同 :");
            for (String message : notSameMessages) {
                System.out.println("    " + message);
            }
        }
        if (!sameMessages.isEmpty()) {
            System.out.println("下面属性相同 :");
            for (String message : sameMessages) {
                System.out.println("    " + message);
            }
        }
        if (!leftNullMap.isEmpty()) {
            System.out.println("下面的属性, " + name1 + " 未配置, " + name2 + " 配置了 :");
            System.out.println(YamlReader.dump(leftNullMap));
        }
        if (!rightNullMap.isEmpty()) {
            System.out.println("下面的属性, " + name1 + " 配置了, " + name2 + " 未配置 :");
            System.out.println(YamlReader.dump(rightNullMap));
        }
        System.out.println("after compare '" + name1 + "' and '" + name2 + "'↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑\n\n\n");
        return StringUtils.join(sameMessages, '\n');
    }
    private static int compare(
            final String prefix,
            Map<String, Object> yaml1,
            Map<String, Object> yaml2,
            final ArrayList<String> notSameMessages, final ArrayList<String> sameMessages, final Map<String, Object> leftNullMap, final Map<String, Object> rightNullMap
    ) {
        int res = 0;

        for (String key : yaml1.keySet()) {
            final Object value1 = yaml1.get(key);
            final Object value2 = yaml2.get(key);

            if (value1 == null && value2 == null) {
                continue;
            } else if (value1 != null && value2 == null) {
                res += 1;
                addPropertiesForYaml(rightNullMap, prefix + key, value1);
            } else if (value1 == null && value2 != null) {
                res -= 1;
                addPropertiesForYaml(leftNullMap, prefix + key, value2);
            } else {
                if (value1 instanceof Map) {
                    if (!(value2 instanceof Map)) {
                        throw new RuntimeException(prefix + key + " is map in yaml1, but in yaml2 is not map, value1=" + JSON.toJSONString(value1) + ", value2=" + JSON.toJSONString(value2));
                    }
                    res += compare(prefix + key + ".", (Map) value1, (Map) value2, notSameMessages, sameMessages, leftNullMap, rightNullMap);
                } else {
                    final int cmp = String.valueOf(value1).compareTo(String.valueOf(value2));
                    res += cmp;
                    if (cmp != 0) {
                        notSameMessages.add(prefix + key + ", value1 = " + value1 + ", value2 = " + value2);
                    } else {
                        sameMessages.add(prefix + key + "=" + value1);
                    }
                }
            }
        }

        for (String key : yaml2.keySet()) {
            if (yaml1.containsKey(key)) continue;
            final Object value2 = yaml2.get(key);

            if (value2 != null) {
                res -= 1;
                addPropertiesForYaml(leftNullMap, prefix + key, value2);
            }
        }

        return res;
    }
    private static void addPropertiesForYaml(Map<String, Object> yaml, String pathStr, Object value) {
        List<String> paths = ListUtil.strToStrList(pathStr, ".");
        for (int i=0; i<paths.size(); ++i) {
            String path = paths.get(i);
            if (i == paths.size()-1) {
                yaml.put(path, value);
                break;
            } else {
                Map<String, Object> child = (Map<String, Object>) yaml.get(path);
                if (null == child) {
                    child = new HashMap<>();
                    yaml.put(path, child);
                }
                yaml = child;
            }
        }
    }


    // yaml1 去掉 yaml2 的属性, 并列出来相交的属性
    public static int leaveOutSameProperties(
            Map<String, Object> yaml1, final String name1,
            Map<String, Object> yaml2, final String name2,
            final String beforeMsg
            ) {
        System.out.println("\n\n");
        if (beforeMsg != null) System.out.println(beforeMsg);
        System.out.println("before leaveOutSameProperties '" + name1 + "' and '" + name2 + "'↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
        final int res = leaveOutSameProperties("", yaml1, name1, yaml2, name2);
        System.out.println("after leaveOutSameProperties '" + name1 + "' and '" + name2 + "'↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑\n\n\n");
        return res;
    }
    private static int leaveOutSameProperties(
            final String prefix,
            Map<String, Object> yaml1, final String name1,
            Map<String, Object> yaml2, final String name2
    ) {
        int res = 0;
        Set<String> removeKeys = new HashSet<>();

        for (String key : yaml1.keySet()) {
            final Object value1 = yaml1.get(key);
            final Object value2 = yaml2.get(key);

            if (value1 == null && value2 == null) {
                removeKeys.add(key);
            } else if (value1 != null && value2 == null) {
            } else if (value1 == null && value2 != null) {
            } else {
                if (value1 instanceof Map) {
                    if (!(value2 instanceof Map)) {
                        throw new RuntimeException(prefix + key + " is map in "+name1+", but in "+name2+" is not map, value1=" + JSON.toJSONString(value1) + ", value2=" + JSON.toJSONString(value2));
                    }
                    res += leaveOutSameProperties(prefix + key + ".", (Map) value1, name1, (Map) value2, name2);
                } else {
                    final int cmp = String.valueOf(value1).compareTo(String.valueOf(value2));
                    if (cmp != 0) {
                        System.out.println(name1+"[" + prefix + key + "] = " + value1 + ", "+name2+"[" + prefix + key + "] = " + value2);
                    }
                    removeKeys.add(key);
                }
            }
        }

        for (String removeKey : removeKeys) {
            yaml1.remove(removeKey);
        }

        return res + removeKeys.size();
    }


    // yaml1 合并 yaml2 的属性, 并列出来 相交 和不相交 的属性
    public static int mergeProperties(
            Map<String, Object> yaml1, final String name1,
            Map<String, Object> yaml2, final String name2,
            final boolean printCopyValues, final boolean printReplaceValues
    ) {
        System.out.println("\n\n\nbefore merge '" + name1 + "' and '" + name2 + "'↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
        final int res = mergeProperties("", yaml1, name1, yaml2, name2, printCopyValues, printReplaceValues);
        System.out.println("after merge '" + name1 + "' and '" + name2 + "'↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑\n\n\n");
        return res;
    }
    private static int mergeProperties(
            final String prefix,
            Map<String, Object> yaml1, final String name1,
            Map<String, Object> yaml2, final String name2,
            final boolean printCopyValues, final boolean printReplaceValues
    ) {
        int res = 0;
        for (String key : yaml2.keySet()) {
            final Object value1 = yaml1.get(key);
            final Object value2 = yaml2.get(key);

            if (value1 == null && value2 == null) {
                continue;
            } else if (value1 != null && value2 == null) {
                continue;
            } else if (value1 == null && value2 != null) {
                if (printCopyValues) System.out.println(name1+"[" + prefix + key + "] is null, merge from "+name2+", value2 = " + JSON.toJSONString(value2));
                yaml1.put(key, value2);
                ++res;
            } else {
                if (value1 instanceof Map) {
                    if (!(value2 instanceof Map)) {
                        throw new RuntimeException(prefix + key + " is map in "+name1+", but in "+name2+" is not map, value1=" + JSON.toJSONString(value1) + ", value2=" + JSON.toJSONString(value2));
                    }
                    res += mergeProperties(prefix + key + ".", (Map) value1, name1, (Map) value2, name2, printCopyValues, printReplaceValues);
                } else {
                    final int cmp = String.valueOf(value1).compareTo(String.valueOf(value2));
                    if (cmp != 0) {
                        if (printReplaceValues) System.out.println(name1+"[" + prefix + key + "] = " + value1 + ", replace by "+name2+"[" + prefix + key + "] = " + value2);
                        yaml1.put(key, value2);
                        ++res;
                    }
                }
            }
        }
        return res;
    }


    /**
     * 特殊的join, 所有的key来自 yaml2
     * 如果 yaml1 有属性 值取自 yaml1, 否则取自 yaml2
     * */
    public static Map<String, Object> specialJoin(
            Map<String, Object> yaml1, final String name1,
            Map<String, Object> yaml2, final String name2,
            final boolean printReplaceValues
    ) {
        System.out.println("\n\n\nbefore specialJoin '" + name1 + "' and '" + name2 + "'↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
        Map<String, Object> resMap = new LinkedHashMap<>();
        specialJoin("", yaml1, name1, yaml2, name2, resMap, printReplaceValues);
        System.out.println("after specialJoin '" + name1 + "' and '" + name2 + "'↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑\n\n\n");
        return resMap;
    }
    private static int specialJoin(
            final String prefix,
            Map<String, Object> yaml1, final String name1,
            Map<String, Object> yaml2, final String name2,
            Map<String, Object> resMap, final boolean printReplaceValues
    ) {
        int resCount = 0;
        for (String key : yaml2.keySet()) {
            final Object value1 = yaml1.get(key);
            final Object value2 = yaml2.get(key);

            if (value1 == null) {
                resMap.put(key, value2);
                ++resCount;
            } else {
                if (value1 instanceof Map) {
                    if (!(value2 instanceof Map)) {
                        throw new RuntimeException(prefix + key + " is map in "+name1+", but in "+name2+" is not map, value1=" + JSON.toJSONString(value1) + ", value2=" + JSON.toJSONString(value2));
                    }
                    final Map<String, Object> subResMap = new LinkedHashMap<>();
                    resMap.put(key, subResMap);
                    resCount += specialJoin(prefix + key + ".", (Map) value1, name1, (Map) value2, name2, subResMap, printReplaceValues);
                } else {
                    final int cmp = String.valueOf(value1).compareTo(String.valueOf(value2));
                    if (cmp != 0) {
                        if (printReplaceValues) System.out.println(name2+"[" + prefix + key + "] = " + value2 + ", replace by "+name1+"[" + prefix + key + "] = " + value1);
                    }
                    resMap.put(key, value1);
                    ++resCount;
                }
            }
        }
        return resCount;
    }



    /**
     * 将properties文件读取的属性map转为 ymal格式的map
     * */
    public static Map<String, Object> convertProperties2YmlMap(Map<String, String> applicationMergedProperties) {
        Map<String, Object> ymlMap = new LinkedHashMap<>();

        for (Map.Entry<String, String> entry : applicationMergedProperties.entrySet()) {
            final String key = entry.getKey();
            final String value = entry.getValue();
            appendToYmlMap(key.split("\\."), value, ymlMap);
        }

        return ymlMap;
    }
    private static void appendToYmlMap(String[] keys, String value, Map<String, Object> ymlMap) {
        for (int keyStartIndex=0; keyStartIndex<keys.length; ++keyStartIndex) {
            final String key = keys[keyStartIndex];

            if (keyStartIndex == keys.length - 1) {
                ymlMap.put(key, value);
                return;
            }

            final Object ymlValue = ymlMap.get(key);
            if (ymlValue == null) {
                Map<String, Object> newMap = new LinkedHashMap<>();
                ymlMap.put(key, newMap);
                ymlMap = newMap;
            } else {
                if (!(ymlValue instanceof Map)) {
                    throw new RuntimeException("非法值");
                }
                ymlMap = (Map) ymlValue;
            }
        }
    }


    public static void main(String[] args) {
    }

}
